﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestConsoleApp
{
    public class TestMultipleThreadSync
    {

    

     


        #region Event
        private static ManualResetEvent mre = new ManualResetEvent(false);

        public static void TestEvent()
        {

            Console.WriteLine("\nStart 3 named threads that block on a ManualResetEvent:\n");

            for (int i = 0; i <= 2; i++)
            {
                Thread t = new Thread(ThreadProc);
                t.Name = "Thread_" + i;
                t.Start();
            }

            Thread.Sleep(500);
            Console.WriteLine("\nWhen all three threads have started, press Enter to call Set()" +
                              "\nto release all the threads.\n");
            Console.ReadLine();

            mre.Set();

            Thread.Sleep(500);
            Console.WriteLine("\nWhen a ManualResetEvent is signaled, threads that call WaitOne()" +
                              "\ndo not block. Press Enter to show this.\n");
            Console.ReadLine();

            for (int i = 3; i <= 4; i++)
            {
                Thread t = new Thread(ThreadProc);
                t.Name = "Thread_" + i;
                t.Start();
            }

            Thread.Sleep(500);
            Console.WriteLine("\nPress Enter to call Reset(), so that threads once again block" +
                              "\nwhen they call WaitOne().\n");
            Console.ReadLine();

            mre.Reset();

            // Start a thread that waits on the ManualResetEvent.
            Thread t5 = new Thread(ThreadProc);
            t5.Name = "Thread_5";
            t5.Start();

            Thread.Sleep(500);
            Console.WriteLine("\nPress Enter to call Set() and conclude the demo.");
            Console.ReadLine();

            mre.Set();

            // If you run this example in Visual Studio, uncomment the following line:
            //Console.ReadLine();
        }

        private static void ThreadProc()
        {
            string name = Thread.CurrentThread.Name;

            Console.WriteLine(name + " starts and calls mre.WaitOne()");

            mre.WaitOne();

            Console.WriteLine(name + " ends.");
        }
        #endregion

        #region Monitor
        private static readonly int MAX_LOOP_TIME = 10;

        private static Queue m_smplQueue = new Queue();

        public static void TestMonitor()
        {
            Thread thread1 = new Thread(new ThreadStart(FirstThread));
            Thread thread2 = new Thread(new ThreadStart(SecondThread));

            thread1.Start();
            thread2.Start();

            thread1.Join();
            thread2.Join();

            Console.WriteLine("Queue Count = "+ GetQueueCount());
            Console.ReadKey();

        }

        private static void FirstThread()
        {
            int counter = 0;
            lock (m_smplQueue)
            {
                while (counter < MAX_LOOP_TIME)
                {

                    Monitor.Wait(m_smplQueue);
                    m_smplQueue.Enqueue(counter);
                    Monitor.Pulse(m_smplQueue);

                    counter++;
                }
            }
        }

        private static void SecondThread()
        {
            int counter = 0;
            lock (m_smplQueue)
            {
                try
                {
                    while (counter < MAX_LOOP_TIME)
                    {
                        Monitor.Pulse(m_smplQueue);
                        while (Monitor.Wait(m_smplQueue, 1000))
                        {

                            int c = (int)m_smplQueue.Dequeue();

                            Console.WriteLine(c);

                            Monitor.Pulse(m_smplQueue);
                          
                            counter++;
                        }
                    }
                }
                catch(Exception ex)
                {


                }
              
            }
        }

        private static int GetQueueCount()
        {
            return m_smplQueue.Count;
        }
        #endregion


        [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>")]
        public static void TestThreadNum()
        {
            ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
            Console.WriteLine($"workerThreads= {workerThreads} , completionPortThreads= {completionPortThreads}");
            unsafe
            {
                Overlapped overlapped = new Overlapped();
                NativeOverlapped* pOverlapped = overlapped.Pack((uint errorCode, uint numBytes, NativeOverlapped* _overlapped) =>
                {
                    ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
                    Console.WriteLine($"workerThreads= {workerThreads} , completionPortThreads= {completionPortThreads}");
                    Console.WriteLine($"here");
                }, null);
                ThreadPool.UnsafeQueueNativeOverlapped(pOverlapped);

            }

        }




    }
}
